package com.hp.docker_base.algorithm;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class BRBInference2 {

    private File b_d;
    private File i_d;
    private File r_i;
    private int continuous_num;
    private int discrete_num;
    private ArrayList<Double> inputStandard;  //参考值的等级

    public BRBInference2(File b_d, File i_d, File r_i, int continuous_num, int discrete_num, ArrayList<Double> inputStandard) {
        this.b_d = b_d;
        this.i_d = i_d;
        this.r_i = r_i;
        this.continuous_num = continuous_num;
        this.discrete_num = discrete_num;
        this.inputStandard = inputStandard;
    }

    public BRBInference2(ArrayList<ArrayList<Double>> belief_degree, ArrayList<ArrayList<Double>> input_data, ArrayList<ArrayList<Double>> rule_input, int continuous_num, int discrete_num, ArrayList<Double> inputStandard) {
        this.continuous_num = continuous_num;
        this.discrete_num = discrete_num;
        this.inputStandard = inputStandard;
        this.belief_degree = belief_degree;
        this.input_data = input_data;
        this.rule_input = rule_input;
    }

    ArrayList<ArrayList<Double>> belief_degree; //规则置信度
    ArrayList<ArrayList<Double>> input_data;  //输入数据
    ArrayList<ArrayList<Double>> rule_input;  //规则数据
    ArrayList<ArrayList<Double>> discrete_rule = new ArrayList<ArrayList<Double>>(); //离散规则数据
    ArrayList<ArrayList<Double>> continuous_rule = new ArrayList<ArrayList<Double>>();
    ; //连续规则数据
    ArrayList<ArrayList<Double>> input_continuous = new ArrayList<ArrayList<Double>>();
    ; // 连续输入数据
    ArrayList<ArrayList<Double>> input_discrete = new ArrayList<ArrayList<Double>>();
    ; // 离散输入数据
    ArrayList<Double> label = new ArrayList<Double>();
    int K;//输入数据的行数
    int N;//后件属性
    int L;//规则数
    int T;//前件属性个数
    int row1;
    int row2;
    public ArrayList<ArrayList<Double>> Activation_weight = new ArrayList<ArrayList<Double>>();
    ArrayList<ArrayList<Double>> m = new ArrayList<ArrayList<Double>>();
    public ArrayList<ArrayList<Double>> m_xin = new ArrayList<ArrayList<Double>>();
    ArrayList<Double> label_inference= new ArrayList<Double>();

    public Double max(ArrayList<Double> data) {   //求最大值
        Double max = data.get(0);
        for (int i = 1; i < data.size(); i++) {
            if (max < data.get(i)) {
                max = data.get(i);
            }
        }
        return max;
    }

    public Double min(ArrayList<Double> data) {  //最小值
        Double min = data.get(0);
        for (int i = 1; i < data.size(); i++) {
            if (min > data.get(i)) {
                min = data.get(i);
            }
        }
        return min;
    }

    public int find_max(ArrayList<Double> data) {   //寻找最大值
        int flag = 0;
        Double max = data.get(0);
        for (int i = 1; i < data.size(); i++) {
            if (max < data.get(i)) {
                max = data.get(i);
            }
        }
        for (int i = 1; i < data.size(); i++) {
            if (data.get(i) == max) {
                flag = i;
                break;
            }
        }
        return flag;
    }

    public static Double sum(ArrayList<Double> data) {  //求和
        Double sum = 0.0;
        for (Double value : data) {
            sum += value;
        }
        return sum;
    }

    public ArrayList<Double> abs(ArrayList<Double> data) {  //绝对值
        ArrayList<Double> data2 = new ArrayList<Double>();
        for (Double value : data) {
            if (value < 0) {
                value = -value;
            }
            data2.add(value);
        }
        return data2;
    }

    public Double abs(Double data) {
        if (data < 0) {
            return -data;
        } else {
            return data;
        }
    }

    public static ArrayList<ArrayList<Double>> transp(ArrayList<ArrayList<Double>> input) {  //转置
        ArrayList<ArrayList<Double>> output = new ArrayList<ArrayList<Double>>();
        for (int j = 0; j < input.get(0).size(); j++) {
            ArrayList<Double> temp = new ArrayList<Double>();
            for (int i = 0; i < input.size(); i++) {
                temp.add(input.get(i).get(j));
            }
            output.add(temp);
        }
        return output;
    }

    public ArrayList<ArrayList<Double>> Trans_continuous(ArrayList<ArrayList<Double>> input, ArrayList<Double> refValue) {
        int m = 2;
        double pVal = 2 / (m - 1);

        ArrayList<ArrayList<Double>> test_membership = new ArrayList<ArrayList<Double>>();
        for (int i = 0; i < input.size(); i++) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (int j = 0; j < refValue.size(); j++) {

                Double membershipSum = 0.0;
                for (int k = 0; k < refValue.size(); k++) {
                    Double membershipTemp = Math.pow((Double) (abs(input.get(i).get(0) - refValue.get(j)) / abs(input.get(i).get(0) - refValue.get(k))), pVal);
                    membershipSum += membershipTemp;
                }
                Temp.add(1.0 / membershipSum);
            }
            test_membership.add(Temp);
        }

        return test_membership;

    }

    public ArrayList<ArrayList<Double>> Trans_discrete(ArrayList<ArrayList<Double>> input, int row1, int row2, ArrayList<ArrayList<Double>> discrete_rule) {

        ArrayList<ArrayList<Double>> s = new ArrayList<ArrayList<Double>>();

        for (int i=0;i<row1;i++) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for(int j=0;j<row2;j++) {
                ArrayList<Double> c = new ArrayList<Double>();
                for(int z=0;z<input.get(i).size();z++) {
                    if(abs(input.get(i).get(z) - discrete_rule.get(j).get(z)) < 0.001 ) {
                        c.add(1.0);
                    }
                }
                Temp.add(sum(c));
            }
            s.add(Temp);
        }

        ArrayList<ArrayList<Double>> b = new ArrayList<ArrayList<Double>>();
        for(int i=0;i<row1;i++) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for(int j=0;j<row2;j++) {
                Temp.add(s.get(i).get(j)/sum(s.get(i)));
            }
            b.add(Temp);
        }

        ArrayList<ArrayList<Double>> test_membership_discrete = transp(b);

        return test_membership_discrete;
    }

    public ArrayList<ArrayList<Double>> Trans_continuous_and_discrete(ArrayList<ArrayList<Double>> test_membership_continuous, ArrayList<ArrayList<Double>> test_membership_discrete, int row1, int row2) {
        ArrayList<ArrayList<Double>> bb = transp(test_membership_continuous);
        ArrayList<ArrayList<Double>> Comprehensive = new ArrayList<ArrayList<Double>>();
        for(int i=0;i<row2;i++) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for(int j=0;j<row1;j++) {
                Temp.add(test_membership_discrete.get(i).get(j)*bb.get(i).get(j));
            }
            Comprehensive.add(Temp);
        }
        return Comprehensive;
    }

    public ArrayList<ArrayList<Double>> weight(ArrayList<ArrayList<Double>> Comprehensive, int row1, int row2, ArrayList<Double> g, ArrayList<Double> h1) {
        ArrayList<ArrayList<Double>> Activation = new ArrayList<ArrayList<Double>>();
        ArrayList<ArrayList<Double>> transp = transp(Comprehensive);
        ArrayList<ArrayList<Double>> Comprehensive_temp = new ArrayList<ArrayList<Double>>();
        for(int i=0;i<transp.size();i++) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (int j=0;j<transp.get(i).size();j++) {
                Temp.add(Math.pow(transp.get(i).get(j),h1.get(T-1)));
            }
            Comprehensive_temp.add(Temp);
        }

        for(int i=0;i<row2;i++) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for(int j=0;j<row1;j++) {
                    Temp.add(g.get(i)*(Math.pow(Comprehensive.get(i).get(j),h1.get(T-1)))/(g.get(i)*(sum(Comprehensive_temp.get(j)))));
            }
            Activation.add(Temp);
        }
        ArrayList<ArrayList<Double>> bb = transp(Activation);

        return bb;
    }

    public ArrayList<ArrayList<Double>> inputTransPiecewise(ArrayList<ArrayList<Double>> input, ArrayList<Double> RF) {
        ArrayList<ArrayList<Double>> inputTrans = new ArrayList<ArrayList<Double>>();

        for(int i=0;i<input.size();++i) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for(int j=0;j< RF.size();++j) {
                Temp.add(0.0);
            }
            inputTrans.add(Temp);
        }

        for(int k=0;k<input.size();++k) {
            for(int i=0;i<input.get(0).size();++i) {
                for (int j = 0; j < (RF.size() - 1); ++j) {
                    if(input.get(k).get(i) > max(RF)) {
                        inputTrans.get(k).set(inputTrans.get(k).size()-1,1.0);
                        break;
                    }
                    if(input.get(k).get(i) < min(RF)) {
                        inputTrans.get(k).set(0,1.0);
                        break;
                    }
                    if ((input.get(k).get(i)>RF.get(j))&&input.get(k).get(i)<RF.get(j+1)) {
                        inputTrans.get(k).set(j,(RF.get(j+1)-input.get(k).get(i))/(RF.get(j+1) - RF.get(j)));
                        inputTrans.get(k).set(j+1,(input.get(k).get(i)-RF.get(j))/(RF.get(j+1) - RF.get(j)));
                        break;
                    }
                }
            }
        }
        return inputTrans;
    }


    /*---------------------------------------------------------------------------------------------------------------------*/

    public static ArrayList<ArrayList<Double>> Load(File file) throws IOException {
        ArrayList<ArrayList<Double>> Output = new ArrayList<ArrayList<Double>>();
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;
        while ((line = br.readLine()) != null) {
            String[] ss = line.split("\t");
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (String s : ss) {
                Temp.add(Double.parseDouble(s));
            }
            Output.add(Temp);
        }
        br.close();
        return Output;
    }

    public void Data_Init() throws IOException {
        /*this.belief_degree = Load(b_d);
        this.input_data = Load(i_d);
        this.rule_input = Load(r_i);*/

        for (ArrayList<Double> value : rule_input) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (int i = 0; i < continuous_num; i++) {
                Temp.add(value.get(i));
            }
            continuous_rule.add(Temp);
        }

        for (ArrayList<Double> value : rule_input) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (int i = continuous_num; i < continuous_num + discrete_num; i++) {
                Temp.add(value.get(i));
            }
            this.discrete_rule.add(Temp);
        }

        for (ArrayList<Double> value : input_data) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (int i = 0; i < continuous_num; i++) {
                Temp.add(value.get(i));
            }
            input_continuous.add(Temp);
        }

        for (ArrayList<Double> value : input_data) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (int i = continuous_num; i < continuous_num + discrete_num; i++) {
                Temp.add(value.get(i));
            }
            input_discrete.add(Temp);
        }

        for (ArrayList<Double> value : input_data) {
            label.add(value.get(value.size() - 1));
        }

        K = input_data.size();
        N = belief_degree.get(0).size();
        L = belief_degree.size();
        T = discrete_num + continuous_num;
        row1 = input_discrete.size();
        row2 = discrete_rule.size();
    }

    public void Parameter() {

        m = this.belief_degree;//规则库
        ArrayList<Double> g = new ArrayList<Double>();  //规则权重
        for (int i = 0; i < L; i++) {
            g.add(1.0);
        }
        ArrayList<Double> h = new ArrayList<Double>();  //属性权重
        for (int i = 0; i < T; i++) {
            h.add(1.0);
        }
        ArrayList<Double> h1 = new ArrayList<Double>();  //属性权重
        for (int i = 0; i < T; i++) {
            h1.add(h.get(i) / max(h));
        }

        //ArrayList<ArrayList<Double>> aa = Trans_continuous(input_continuous, inputStandard);
        ArrayList<ArrayList<Double>> aa = inputTransPiecewise(input_continuous, inputStandard);

        ArrayList<ArrayList<Double>> test_membership_continuous = new ArrayList<ArrayList<Double>>();
        for (int i = 0; i < row1; i++) {
            ArrayList<Double> Temp = new ArrayList<Double>();
            for (int j = 0; j < row2; j++) {
                if (continuous_rule.get(j).get(continuous_num - 1) == 1.0) {
                    Temp.add(aa.get(0).get(0));
                } else if (continuous_rule.get(j).get(continuous_num - 1) == 2.0) {
                    Temp.add(aa.get(0).get(1));
                }else if (continuous_rule.get(j).get(continuous_num - 1) == 3.0) {
                    Temp.add(aa.get(0).get(2));
                }
            }
            test_membership_continuous.add(Temp);
        }

        ArrayList<ArrayList<Double>> test_membership_discrete = Trans_discrete(input_discrete, row1, row2, discrete_rule);
        ArrayList<ArrayList<Double>> Comprehensive = Trans_continuous_and_discrete(test_membership_continuous, test_membership_discrete, row1, row2);
        Activation_weight = weight(Comprehensive, row1, row2, g, h1);
    }

    public void fusion() {
        for(int i=0;i<row1;i++) {
            ArrayList<Double> m_xin_temp= new ArrayList<Double>();
            double b = 1.0;
            for(int k=0;k<L;k++) {
                b = b*(1-Activation_weight.get(i).get(k)*sum(m.get(k)));
            }
            double b1 = (N - 1) * b;
            ArrayList<Double> b2 = new ArrayList<Double>();
            for(int j=0;j<N;j++) {
                double b3 = 1.0;
                for(int k=0;k<L;k++) {
                    b3 = b3 *(Activation_weight.get(i).get(k)*m.get(k).get(j)+1-Activation_weight.get(i).get(k)*sum(m.get(k)));
                }
                b2.add(b3);
            }
            double u = 1.0 / (sum(b2) - b1);

            double c = 1.0;
            for(int k=0;k<L;k++) {
                c = c*(1-Activation_weight.get(i).get(k));
            }
            for(int j=0;j<N;j++) {
                m_xin_temp.add(u*(b2.get(j)-b)/(1.0-u*c));
            }
            m_xin.add(m_xin_temp);

            label_inference.add(Double.valueOf(find_max(m_xin.get(i))+1));
        }

        System.out.println();
    }

}
